package com.bsoft.client.processor;

import com.bsoft.client.annotation.RpcAutowired;
import com.bsoft.client.common.RequestMetadata;
import com.bsoft.client.proxy.RpcProxy;
import com.bsoft.client.proxy.RpcProxyFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

/**
 * 该类在spring容器初始化加载完BeanFactory之后，可以拿到所有的BeanDefinition，筛选出目标bean进行动态代理，创建远程访问的代理类
 */
@Slf4j
public class RpcClientProcessor implements BeanFactoryPostProcessor, ApplicationContextAware {
    private ApplicationContext applicationContext;
    private RequestMetadata metadata;

    public RpcClientProcessor(RequestMetadata metadata) {
        this.metadata = metadata;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 遍历所有BeanDefinition，找到被@RpcAutowired注解注释的bean
        for (String beanDifinitionName : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDifinitionName);
            String className = beanDefinition.getBeanClassName();
            if (className != null) {
                // 根据类名解析到具体类对象
                Class<?> clazz = ClassUtils.resolveClassName(className, this.getClass().getClassLoader());
                // 通过反射工具对该类的所有属性进行处理
                ReflectionUtils.doWithFields(clazz, field -> {
                    // 判断该属性是否加了@RpcAutowired注解
                    RpcAutowired rpcAutowired = AnnotationUtils.getAnnotation(field, RpcAutowired.class);
                    if (rpcAutowired != null) {
                        // 从容器中拿到这个bean
                        Object bean = this.applicationContext.getBean(clazz);
                        field.setAccessible(true);
                        // 为该属性增加代理类
                        RpcProxy proxy = RpcProxyFactory.getProxyInstance(field.getType());
                        ReflectionUtils.setField(field, bean, proxy.proxyInterface(metadata, field.getType()));
                    }
                });
            }
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
